package cn.git.agent.match;

import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.named;

/**
 * @description: 多个注解拦截
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-12-24
 */
public class MultiAnnotationMatch implements IndirectMatch {

    /**
     * 注解名称列表
     */
    private List<String> annotationNameList;

    /**
     * 构造函数
     *
     * @param annotationNames 注解名称列表
     */
    private MultiAnnotationMatch(String... annotationNames) {
        if (annotationNames == null || annotationNames.length == 0) {
            throw new IllegalArgumentException("classNames can not be null or empty");
        }
        this.annotationNameList = Arrays.asList(annotationNames);
    }

    /**
     * 类名构建匹配规则
     * eg: ElementMatchers.isAnnotatedWith(ElementMatchers.named(CONTROLLER_NAME)
     *     .and(ElementMatchers.named(REST_CONTROLLER_NAME))...
     *
     * @return
     */
    @Override
    public ElementMatcher.Junction<? super TypeDescription> buildJunction() {
        ElementMatcher.Junction<? super TypeDescription> junction = null;
        for (String annotationName : annotationNameList) {
            if (junction == null) {
                junction = isAnnotatedWith(named(annotationName));
            } else {
                junction = junction.and(isAnnotatedWith(named(annotationName)));
            }
        }

        return junction;
    }

    /**
     * 用于当前匹配器匹
     * 用于判断 typeDescription 是否满足 IndirectMatch 的实现
     *
     * @param typeDescription
     * @return
     */
    @Override
    public boolean isMatch(TypeDescription typeDescription) {
        /**
         * 比如annotationNameList = [xxx.xxx.Aannotation, xxx.xxx.Bannotation]
         * typeDescription上的注解是 @Aannotation(xxx) and @BAnnotation(yyy) true 否则 false
         */
        List<String> annotationList = new ArrayList<>(annotationNameList);

        // 获取typeDescription上的注解名称
        AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
        for (AnnotationDescription annotationDescription : declaredAnnotations) {
            // 获取注解的全类名
            String actualName = annotationDescription.getAnnotationType().getActualName();
            annotationList.remove(actualName);
        }
        return annotationList.isEmpty();
    }

    public static IndirectMatch byMultiAnnotationMatch(String... annotationNames) {
        return new MultiAnnotationMatch(annotationNames);
    }
}
